#include "resource.h"
#include "miniz.h"
#include <cstring>
#include <memory>
#include "logger.h"
#include "binary_res.h"

static std::string MimeType(const std::string &sName) {
  auto nIdx = sName.find_last_of(".");
  if (nIdx == std::string::npos || nIdx == sName.size() - 1)
    return "text/plain";

  auto sExt = sName.substr(nIdx + 1, sName.size() - nIdx - 1);
  if (sExt == "html" || sExt == "htm" || sExt == "shtm" || sExt == "shtml") {
    return "text/html";
  } else if (sExt == "css") {
    return "text/css";
  } else if (sExt == "js") {
    return "application/x-javascript";
  } else if (sExt == "ico" || sExt == "icon") {
    return "image/x-icon";
  } else if (sExt == "gif") {
    return "image/gif";
  } else if (sExt == "jpg" || sExt == "jpeg") {
    return "image/jpeg";
  } else if (sExt == "png") {
    return "image/png";
  } else if (sExt == "svg") {
    return "image/svg+xml";
  } else if (sExt == "txt") {
    return "text/plain";
  } else if (sExt == "xml" || sExt == "xslt" || sExt == "xsl") {
    return "text/xml";
  } else if (sExt == "ttf") {
    return "application/x-font-ttf";
  } else {
    return "text/plain";
  }
}

Resource::~Resource() {
  for (auto &kv : _mAssets) {
    free(kv.second.pData);
  }

  if (_pZip) {
    mz_zip_reader_end(_pZip);
    delete _pZip;
  }

  _mAssets.clear();
}

Resource &Resource::Instance() {
  static std::unique_ptr<Resource> GIns;
  if (!GIns)
    GIns.reset(new Resource);
  return *GIns;
}

bool Resource::Load() {
  const void *pData = binary_res_zip;
  size_t nSize = binary_res_zip_size;

  _pZip = new mz_zip_archive_tag;
  memset(_pZip, 0, sizeof(mz_zip_archive_tag));

  if (!mz_zip_reader_init_mem(_pZip, pData, nSize, 0))
    return false;

  mz_uint nCount = mz_zip_reader_get_num_files(_pZip);
  for (mz_uint nIdx = 0; nIdx < nCount; ++nIdx) {
    mz_zip_archive_file_stat iStat;
    if (mz_zip_reader_is_file_a_directory(_pZip, nIdx) ||
        !mz_zip_reader_file_stat(_pZip, nIdx, &iStat))
      continue;

    std::string sType = MimeType(iStat.m_filename);
    Asset iAsset;
    memset(&iAsset, 0, sizeof(iAsset));

    iAsset.pData =
        (char *)mz_zip_reader_extract_to_heap(_pZip, nIdx, &iAsset.nSize, 0);
    strncpy(iAsset.pType, sType.data(), sType.size());

    _mAssets[iStat.m_filename] = iAsset;
  }

  return true;
}

Asset *Resource::Get(const std::string &sPath) {
  auto it = _mAssets.find(sPath);
  if (it == _mAssets.end()) {
    LOG_ERR("cant find asset %s\n", sPath.c_str());
    return nullptr;
  }

  return &it->second;
}
